from transformers import AutoTokenizer, AutoModel
import os
import re
from flask import request, jsonify, Blueprint, stream_with_context
import json
import random
import math
import datetime

from ..util import success_res, fail_res
from ..model import Question, AutoQuestion, AutoScore
from .. import db, app
from ..llm import llm_model, model_name

chatglm_bp = Blueprint('chatglm', __name__)

# 1选择；3填空（3.1，大模型出题文本比对校验效果较低，换3.2大模型出题大模型答题校验效果适中，3大模型出词正则出题）
question_formmaters = {
    1: """
        你是一个专业的选择题出题老师，基于给定的文本内容，出3-5个选择题，其中抠选出信息是该文本片段中包含的关键信息，包括时间、地点、组织机构、关键词、人物、武器装备、基地等重要信息。
        严格遵守下列要求：
        返回标准的json格式，注意是多个选择题样本，因此返回数组类型，格式如下：[{{"问题": question, "选项": {{options}}, "答案": answer}}, {{"问题": question, "选项": {{options}}, "答案": answer}}]
        答案是单个字母字符，只能是"A"、"B"、"C"或"D"
        问题形式，要么用符号【】替代问题中抽取的关键信息，要么用疑问句对抽取的关键信息进行提问
        
        例如：
        文本内容：日向级护卫舰（ひゅうが型護衛艦）是日本海上自卫队旗下的一个直升机护卫舰（Helicopter Destroyer, DDH）舰级。本级舰共两艘，首舰日向号于2006开工，2009年3月18日就役。二号舰伊势号，这一舰名源自日本古代的伊势国，即现在的三重县。于2011年3月16日就役。
        选择题：
        [
            {{
                "问题": "日向级护卫舰是【】旗下的一个直升机护卫舰（Helicopter Destroyer, DDH）舰级。",
                "选项": {{"A": "美国海军", "B": "日本海上自卫队", "C": "韩国海军", "D": "中国海军"}},
                "答案": "B"
            }},
            {{
                "问题": "日向级护卫舰本级舰共两艘，首舰【】于2006开工，2009年3月18日就役。",
                "选项": {{"A": "羽黑号", "B": "舰伊势号", "C": "日向号", "D": "摩耶号"}},
                "答案": "C"
            }}
        ]
        
        以下述文本内容出题
        文本内容：{content}
        仅输出选择题
    """,
    3: """
        你是一个专业的填空题出题老师，基于给定的文本内容，分解出1-5个重要的文本片段，从文本片段中抽取出关键信息，包括时间、地点、组织机构、关键词、人物、武器装备、基地等关键信息。
        返回标准的json格式，注意是多个关键信息样本，因此返回数组类型。
        关键信息是通过文本片段做关键词抽取，从中选择最关键的1-3个词语，词语不做任何改动。文本片段中，删除关键词，原位置用符号【】代替。
        格式如下：[{{"文本片段": content, "关键信息": [word]}}]

        例如：
        文本内容：日向级护卫舰是日本海上自卫队旗下的一个直升机护卫舰舰级。本级舰共两艘，首舰日向号于2006开工，2009年3月18日就役，二号舰伊势号，这一舰名源自日本古代的伊势国，即现在的三重县。于2011年3月16日就役。
        填空题：
        [
            {{
                "文本片段": "日向级护卫舰是【】旗下的一个直升机护卫舰舰级。",
                "关键信息": ["日本海上自卫队"]
            }},
            {{
                "文本片段": "日向级护卫舰本级舰共两艘，首舰【】于2006开工，2009年3月18日就役，二号【】，于2011年3月16日就役。",
                "关键信息": ["日向号", "舰伊势号"]
            }}
        ]

        以下述文本内容出题
        文本内容：{content}
        仅输出填空题
        """,
}

answer_formatters = {
    1: """
        你是一个专业的选择题答题学生，基于给定的文本内容和选项，回答选择题，请直接给出答案，返回答案必须是选项主键大写字母字符串。

        例如：
        文本内容：卡-26/126是为农业和其他空中作业研制的多功能直升机，1965年首飞。引人注目的是它的驾驶舱后面安装了可互换模块，可针对客运/货运、空中救护、消防及其他用途而进行调换。1970年，卡-26/126直升机在前苏联开始了它的服役生涯。该机型共计交付了超过850架。
        问题：卡-26/126是为【】和空中作业研制的多功能直升机。
        选项: {{"A": "重工业", "B": "轻工业", "C": "农业", "D": "旅游业"}}
        答案："C"
        问题：1970年，卡-26/126直升机在【】开始了它的服役生涯。
        选项: {{"A": "德国", "B": "前苏联", "C": "俄罗斯", "D": "乌克兰"}}
        答案："B"

        文本内容：{content}
        选项：{options}
        问题：{question}
        仅输出答案：
        """,
    3: """
        你是一个专业的填空题答题学生，基于给定的文本内容，回答填空题，请直接给出答案，返回答案可能是多个字符串，所以必须是数组类型，返回格式严格遵守JSON标准格式。
        格式如下：["答案1", "答案2"]

        例如：
        文本内容：卡-26/126是为农业和其他空中作业研制的多功能直升机，1965年首飞。引人注目的是它的驾驶舱后面安装了可互换模块，可针对客运/货运、空中救护、消防及其他用途而进行调换。1970年，卡-26/126直升机在前苏联开始了它的服役生涯。该机型共计交付了超过850架。
        问题：卡-26/126是为【】和【】研制的多功能直升机。
        答案：["农业", "空中作业"]
        问题：1970年，卡-26/126直升机在【】开始了它的服役生涯。
        答案：["前苏联"]

        文本内容：{content}
        问题：{question}
        仅输出答案：
        """
}

adv_subjective_question_prompt_example_formmater = """
        示例{ques_idx}：
        材料：
        {info}
        问题：
        {question}
        标准答案：
        {standard_answer}
        待判答案：
        {answer}
        评分理由和得分：
        {{"评分理由": {reason}, "得分": {score}}}
        """

subjective_question_prompt_example_formmater = """
        示例{ques_idx}：
        标准答案：
        {standard_answer}
        待判答案：
        {answer}
        评分理由和得分：
        {{"评分理由": {reason}, "得分": {score}}}
        """

subjective_question_prompt_example_formmater_bak = """
        示例{ques_idx}：
        问题：
        {question}
        标准答案：
        {standard_answer}
        待判答案：
        {answer}
        评分理由和得分：
        {{"评分理由": {reason}, "得分": {score}}}
        """

subjective_question_formmaters_bak = {
    4: """
        你是一个专业的判分老师，对任务中的待判答案进行评分，解析任务的JSON数据，基于任务的问题和标准答案，通过计算任务的待判答案和标准答案之间的文本相似度，对待判答案给出评分理由和得分，其中标准答案的得分是满分10分，判分得分不得超过10分。
        判分原则：1、待判答案与标准答案的文本对比评估指标（如Rouge、向量相似度、BLEU等）越高，得分越高；2、分析待判答案的主要内容与标准答案的主要内容，基于两者主要内容的相似度判定得分：两者主要内容大部分相同，判定为紧密相关，紧密相关得8-10分；两者内容有部分相同，较为紧密得5-7分；两者只有少数相同，一般紧密得2-4分；两者没有相同，毫不相关得1分；待判答案为空，不作答得0分。
        输出格式是标准的json格式，包括评分理由和得分，评分理由是字符串形式，得分是数值形式。格式如下：{{"评分理由": "理由", "得分": score}}

        {ques_example}

        任务
        问题：
        {ques_title}
        标准答案：
        {ques_answer}
        待判答案：
        {answer}
        输出评分理由和得分
    """,
}

subjective_question_formmaters = {
    4: """
        你是一个专业的判分老师，对输入中的待判答案进行评分，基于输入的标准答案，通过计算任务的待判答案和标准答案之间的文本相似度，对待判答案给出评分理由和得分，其中标准答案的得分是满分10分，判分得分不得超过10分。
        判分原则：1、待判答案与标准答案的文本对比评估指标（如Rouge、向量相似度、BLEU等）越高，得分越高；2、分析待判答案的主要内容与标准答案的主要内容，基于两者主要内容的相似度判定得分：两者主要内容大部分相同，判定为紧密相关，紧密相关得8-10分；两者内容有部分相同，较为紧密得5-7分；两者只有少数相同，一般紧密得2-4分；两者没有相同，毫不相关得1分；待判答案为空，不作答得0分。
        输出格式是标准的json格式，包括评分理由和得分，评分理由是字符串形式，得分是数值形式。格式如下：{{"评分理由": "理由", "得分": score}}

        {ques_example}

        输入
        {input_example}
        输出评分理由和得分
    """,
}

subject_example_prompt_formater = lambda x, y: json.dumps({'标准答案': x, '待判答案': y}, ensure_ascii=False)

subjective_question_response_re_formater = '\{[\n ]*"评分理由": \"(.*)\"[,\n ]*"得分": ([\d\.]*)[\n 分]*\}'


# 出题的答案检测
def check_question_expert_status(ques_tagid, content, ques_title, ques_answer: str, ques_options: str):
    total_count = 1
    accur_count = 0
    flag = False
    expert_status = 0
    try:
        # print("try", answer_formatters[ques_tagid], flush=True)
        input = ''
        if ques_tagid == 1:
            input = answer_formatters[ques_tagid].format(content=content, question=ques_title, options=ques_options)
        elif ques_tagid == 3:
            input = answer_formatters[ques_tagid].format(content=content, question=ques_title)
        # print(input, flush=True)
        if input:
            response = llm_model.chat(input)
            # print('ques_answer in check_question_expert_status', ques_answer, flush=True)
            print('response in check_question_expert_status', response, flush=True)
            if ques_tagid == 1:
                re_ques_answer = re.match('^"?(.{1})"?$', ques_answer)
                re_expert_answer = re.match('^[答案："]*(.{1})"?$', response)
                # print('re_ques_answer', re_ques_answer, flush=True)
                # print('re_expert_answer', re_expert_answer, flush=True)
                if re_ques_answer and re_expert_answer:
                    ques_answer_option = re_ques_answer.group(1)
                    expert_answer_option = re_ques_answer.group(1)
                    expert_status = accur_count = ques_answer_option == expert_answer_option
                    # print('expert_status', ques_answer_option == expert_answer_option, flush=True)
                else:
                    expert_status = 0
            elif ques_tagid == 3:
                print('*' * 5, ques_answer, flush=True)
                ques_answer = json.loads(ques_answer)
                print(ques_answer, flush=True)
                expert_answer = json.loads(response)
                total_count = len(ques_answer)
                while ques_answer and expert_answer:
                    ques_answer_item = ques_answer.pop(0)
                    expert_answer_item = expert_answer.pop(0)
                    if ques_answer_item == expert_answer_item:
                        accur_count += 1
                expert_status = accur_count == total_count
            flag = True
        else:
            print("答案检测input为空", flush=True)
    except Exception as e:
        print(f"答案检测异常: {str(e)}", flush=True)
    return flag, expert_status, accur_count, total_count


# json格式
def llm_create_objective_question(content, ques_tagid, batch=False, datacollection_name=None):
    """
    params: content: 题干来源材料
    params: ques_tagid: 题型: 1选择3填空
    """
    # print(ques_tagid, question_formmaters[ques_tagid], flush=True)
    input = question_formmaters[ques_tagid].format(content=content)
    print(' - ' * 20, flush=True)
    print('input：', input, flush=True)
    response = llm_model.chat(input)

    flag, data = True, []
    try:
        print('客观题：', response, flush=True)
        if ques_tagid == 1:
            question_list = re.findall('"问题":\s?"(.*)",[\s\n]*"选项":\s?{?(.*)}?,[\s\n]*{?"答案":\s?"(.*)"', response)

            # print('-*- ' * 10, flush=True)
            # print('question_list is', question_list, flush=True)

            if question_list:
                for ques_item in question_list:
                    # print('-' * 10, len(ques_item), flush=True)
                    # print(ques_item, flush=True)

                    ques_title = ques_item[0]
                    ques_option_options = re.findall('"(\w){1}":\s"(.+?)"', ques_item[1])
                    ques_answer = ques_item[2]

                    # print('+' * 10, flush=True)
                    # print(ques_option_options, flush=True)

                    ques_options = {option[0]: option[1] for option in ques_option_options}
                    ques_options_str = json.dumps(ques_options, ensure_ascii=False)

                    ques_word_tags = ['哪', '什么', '?', '？', '【】', '()', '（ ）']

                    def check_is_question(content):
                        for tag in ques_word_tags:
                            if tag in content:
                                return True
                        return False

                    status = 0
                    re_ques_answer = re.match('^"?(.{1})"?$', ques_answer)
                    if check_is_question(ques_title) and re_ques_answer:
                        ques_answer = re_ques_answer.group(1)
                        status = 1

                    if batch:
                        # 主观题入库，在question.py的create_question接口中
                        _, expert_status, accur_count, total_count = check_question_expert_status(ques_tagid, content,
                                                                                                  ques_title,
                                                                                                  ques_answer,
                                                                                                  ques_options_str)

                        # ques_title += '\n' + ques_options_str

                        try:
                            aq = AutoQuestion(content=content, output_chat=response, ques_tagid=ques_tagid,
                                              output_title=ques_title, output_options=ques_options,
                                              output_answer=ques_answer,
                                              output_accur_count=accur_count, output_total_count=total_count,
                                              expert_status=expert_status, status=status,
                                              model_name=model_name, datacollection_name=datacollection_name)
                            db.session.add(aq)
                            db.session.commit()
                        except:
                            db.session.rollback()

                    data.append({'ques_title': ques_title, 'ques_answer': ques_answer, "ques_options": ques_options,
                                 'ques_tagid': ques_tagid})
            else:
                flag, data = False, "题目完整度不足"
        elif ques_tagid == 3:
            context_answers_list = re.findall('"文本片段":\s?"(.*)",\n*\s*"关键信息":\s?\[(.*)\]', response)
            if context_answers_list:
                for context_answers_item in context_answers_list:
                    ques_title_content = context_answers_item[0]
                    answers_str = context_answers_item[1]
                    ques_answer_words = re.findall('"(.+?)"', answers_str)

                    ques_answer_idx = []
                    for ques_answer_word in ques_answer_words:
                        word_split = re.split(ques_answer_word, ques_title_content, 1)
                        if len(word_split) > 1:
                            ques_answer_idx.append(
                                {'word': ques_answer_word, 'idx': ques_title_content.index(ques_answer_word)})
                            ques_title_content = '【】'.join(word_split)

                    ques_answer = [i['word'] for i in sorted(ques_answer_idx, key=lambda x: x['idx'])]
                    ques_answer_str = json.dumps(ques_answer, ensure_ascii=False)

                    if batch:
                        status = 1 if '【】' in ques_title_content else 0
                        accur_count = len(ques_answer)
                        total_count = len(ques_answer_words)
                        expert_status = 1 if len(ques_answer) == len(ques_answer_words) else 0

                        try:
                            aq = AutoQuestion(content=content, output_chat=response, ques_tagid=ques_tagid,
                                              output_title=ques_title_content,
                                              output_answer=ques_answer_str,
                                              output_accur_count=accur_count, output_total_count=total_count,
                                              expert_status=expert_status, status=status,
                                              model_name=model_name, datacollection_name=datacollection_name)
                            db.session.add(aq)
                            db.session.commit()
                        except:
                            db.session.rollback()

                    data.append(
                        {'ques_title': ques_title_content, 'ques_answer': ques_answer, 'ques_tagid': ques_tagid})
            else:
                flag, data = False, "题目完整度不足"
    except Exception as e:
        print(f"Exception in llm_create_objective_question: {str(e)}", flush=True)
        flag, data = False, "自动出题异常"

    return flag, data


@chatglm_bp.route('/content_create_question', methods=['POST'])
def content_create_question():
    content = request.json.get('content', '')
    ques_tagid = request.json.get('ques_tagid', 1)
    if question_formmaters.get(ques_tagid, ''):
        flag, res = llm_create_objective_question(content, ques_tagid)
        if flag:
            return success_res(data=res)
        else:
            return fail_res(msg=f"题目创建出错，{res}")
    else:
        return fail_res(msg="没有该题型自动出题")


'''
    def generate():
        yield 'Hello '
        yield request.args['name']
        yield '!'

    return question_bp.response_class(stream_with_context(generate()))
'''

gaokao_file = os.path.join(os.getcwd(), 'static', 'bench.json')
gaokao_questions = []
with open(gaokao_file, 'r', encoding='utf-8') as f:
    gaokao_data = json.loads(f.read())
    gaokao_questions = gaokao_data['example']


def get_ques_content(content):
    # print(content, flush=True)
    return re.search('[0-9]*[\.|．](（\s*[0-9]*分）)?([\S\s]*)', content).group(2)


def sub_signal_blank(context):
    context = re.sub('[,./?:;"\'\{\}\s!@#$%&\(\)，。、？：；“‘’”【】！]', '', context)
    return context


def get_chatglm_score_by_gaokao(ques_title, standard_answer, model_output):
    # print(sub_signal_blank(standard_answer), flush=True)
    # print(sub_signal_blank(model_output), flush=True)
    if sub_signal_blank(standard_answer) == sub_signal_blank(model_output):
        return 1, 10, '与标准答案基本一致，可获满分', ''
    questions = [{
        "information": "家庭农场是指以家庭成员为主要劳动力，从事农业规模化、集约化、商品化生产经营，并以农业收入为家庭主要收入来源的农业组织形式。2013年中央“一号文件”首次提出发展家庭农场。2019年中央“一号文件”提出“全面深化农村改革，激发乡村发展活力”，并再次强调要坚持家庭经营基础性地位，突出培育家庭农场等新型农业经营主体。\n近年来，我国家庭农场发展迅速，数量已超过87.7万户。据2019年农业农村部信息：\n我国家庭农场大多由小农户升级而来，经营规模在20～200亩之间；家庭农场主要从事种植业、养殖业和种养结合，其中种植类农场有56.1 % 采用了喷灌技术，养殖类农场有近80 % 进行了粪便资源化、综合循环利用和无害化处理；在不少家庭农场中，父辈负责生产，子女负责营销，经营的农产品有以自己名字命名的品牌；全国有36.9 % 的家庭农场加入了农民合作社，参与和分享农机、良种、技术、订单等服务。",
        "question": "结合材料并运用经济知识，说明发展家庭农场对于激发乡村经济活力的积极作用。",
        "standard_answer": "①促进农村土地流转与规模经营，提高农业劳动生产率；\n②促使先进农业技术应用，提高农产品产量和品质；\n③推进农业品牌化、专业化经营，增强农产品市场竞争力；\n④拓宽农民合作社服务范围，推动乡村产业融合发展。",
        "answer": "发展家庭农场对于激发乡村经济活力的积极作用主要体现在以下几个方面：1.提高农业生产效率，推动农业规模化、集约化、商品化。2.带动农业技术的更新和提高，提高农业生产效率，降低农业生产成本，提高农产品的质量和产量。3.带动农产品的品牌化，提高农产品的附加值，增加农业收入。4.推动农民合作社的发展，通过共享农机、良种、技术、订单等服务，提高农业生产效率，降低农业生产成本，提高农业收入。",
        "reason": "待判答案涵盖了标准答案中的四个主要点，即提高农业生产效率、促使先进农业技术、推进农产品品牌化以及推动乡村产业融合发展。学生的答案不仅重述了材料中的信息，还结合了经济知识，对家庭农场激发乡村经济活力的积极作用进行了全面的说明。因此，学生的答案符合标准答案的要求，应给予满分。",
        "score": 10
        # }, {
        #     "information": "新型冠状病毒肺炎是近百年来人类遭遇的影响范围最广的全球性大流行病，对全世界是一次严重危机和严峻考验。人类生命安全和健康面临重大威胁。\n面对突如其来、来势汹汹的疫情天灾，中国果断打响疫情防控阻击战，把人民生命安全和身体健康放在第一位，采取最全面最严格最彻底的防控措施，取得了抗击疫情重大战略成果。中国始终秉持人类命运共同体理念，肩负大国担当，同其他国家并肩作战、共克时艰，毫无保留同各方分享防控和救治经验，尽己所能向国际社会提供人道主义援助，支持全球抗击疫情。\n2020年3月26日，国家主席习近平出席二十国集团领导人特别峰会并发表《携手抗疫共克时艰》讲话，倡议打好新冠肺炎疫情防控全球阻击战，有效开展国际联防联控，积极支持国际组织发挥作用，加强国际宏观经济政策协调。",
        #     "question": "结合材料并运用政治生活知识，分析打赢新冠肺炎疫情防控全球阻击战为什么要秉持人类命运共同体理念。",
        #     "standard_answer": "①国家利益是国际关系的决定因素，共同利益是国际合作的基础。秉持人类命运共同体理念，加强国际合作，携手赢得这场人类同重大传染性疾病的斗争，是各国共同利益之所在。\n②和平与发展是当今时代的主题（或：维护世界和平、促进共同发展是我国外交政策的宗旨）。中方秉持人类命运共同体理念，愿向其他国家提供力所能及的援助，为世界经济稳定作出贡献。\n③秉持人类命运共同体理念符合我国外交政策中维护国家主权、安全和发展利益，促进世界和平与发展的目标；符合我国平等互利、和平共处的外交基本准则。\n④在当今的国际社会，维护和保障人权是一项基本道义原则。是否合乎保障人权的要求已成为评判一个集体（无论是政治上的还是经济上的）优劣的重要标准。坚持人类命运共同体理念，坚决打赢疫情防治攻坚战，有利于尊重和保障人权。\n⑤我国是人民民主专政的社会主义国家，人民是国家的主人，坚持人类命运共同体理念，是保障人民主人翁地位的体现。",
        #     "answer": "打赢新冠肺炎疫情防控全球阻击战需要秉持人类命运共同体理念，因为新冠肺炎疫情是全球性的大流行病，影响范围广泛，对全世界构成严重危机和严峻考验。这种理念强调全球的团结和协作，而不是分裂和对抗。只有各国共同努力，才能有效地防控疫情，保护人类的生命安全和健康。此外，这也体现了中国作为一个大国的责任和担当，愿意同其他国家并肩作战、共克时艰，分享防控和救治经验，提供人道主义援助，支持全球抗击疫情。",
        #     "reason": "学生的答案基本上符合标准答案的要求，但是在表述上略显简略，没有完全展开分析，缺少了对国家利益、和平与发展、外交政策宗旨、人权保障等方面的具体阐述。因此，可以给予部分分数。\n1. 对于提到的全球性大流行病和全球团结协作的部分，可以给予部分分数。\n2. 对于提到的中国作为大国的责任和担当，可以给予部分分数。\n3. 由于学生答案没有涉及到国家利益、和平与发展、外交政策宗旨、人权保障等方面的具体分析，扣去相应的分数。",
        #     "score": 5.83
    }, {
        "information": "家庭农场是指以家庭成员为主要劳动力，从事农业规模化、集约化、商品化生产经营，并以农业收入为家庭主要收入来源的农业组织形式。2013年中央“一号文件”首次提出发展家庭农场。2019年中央“一号文件”提出“全面深化农村改革，激发乡村发展活力”，并再次强调要坚持家庭经营基础性地位，突出培育家庭农场等新型农业经营主体。\n近年来，我国家庭农场发展迅速，数量已超过87.7万户。据2019年农业农村部信息：\n我国家庭农场大多由小农户升级而来，经营规模在20～200亩之间；家庭农场主要从事种植业、养殖业和种养结合，其中种植类农场有56.1 % 采用了喷灌技术，养殖类农场有近80 % 进行了粪便资源化、综合循环利用和无害化处理；在不少家庭农场中，父辈负责生产，子女负责营销，经营的农产品有以自己名字命名的品牌；全国有36.9 % 的家庭农场加入了农民合作社，参与和分享农机、良种、技术、订单等服务。",
        "question": "结合材料并运用经济知识，说明发展家庭农场对于激发乡村经济活力的积极作用。",
        "standard_answer": "①促进农村土地流转与规模经营，提高农业劳动生产率；\n②促使先进农业技术应用，提高农产品产量和品质；\n③推进农业品牌化、专业化经营，增强农产品市场竞争力；\n④拓宽农民合作社服务范围，推动乡村产业融合发展。",
        "answer": "发展家庭农场在以下几个方面起到了积极作用：1.推动农业规模化、集约化、商品化。2.降低农业生产成本，提高农产品的质量和产量。3.提高农产品的附加值，增加农业收入。4.推动农民合作社的发展。",
        "reason": "答案与标准答案紧密相关，待判答案涵盖了标准答案中的四个主要点，即提高农业生产效率、推动农业技术更新、农产品品牌化以及推动农民合作社的发展，但描述简短没有扩展和详细描述。",
        "score": 8
    }, {
        "information": "家庭农场是指以家庭成员为主要劳动力，从事农业规模化、集约化、商品化生产经营，并以农业收入为家庭主要收入来源的农业组织形式。2013年中央“一号文件”首次提出发展家庭农场。2019年中央“一号文件”提出“全面深化农村改革，激发乡村发展活力”，并再次强调要坚持家庭经营基础性地位，突出培育家庭农场等新型农业经营主体。\n近年来，我国家庭农场发展迅速，数量已超过87.7万户。据2019年农业农村部信息：\n我国家庭农场大多由小农户升级而来，经营规模在20～200亩之间；家庭农场主要从事种植业、养殖业和种养结合，其中种植类农场有56.1 % 采用了喷灌技术，养殖类农场有近80 % 进行了粪便资源化、综合循环利用和无害化处理；在不少家庭农场中，父辈负责生产，子女负责营销，经营的农产品有以自己名字命名的品牌；全国有36.9 % 的家庭农场加入了农民合作社，参与和分享农机、良种、技术、订单等服务。",
        "question": "结合材料并运用经济知识，说明发展家庭农场对于激发乡村经济活力的积极作用。",
        "standard_answer": "①促进农村土地流转与规模经营，提高农业劳动生产率；\n②促使先进农业技术应用，提高农产品产量和品质；\n③推进农业品牌化、专业化经营，增强农产品市场竞争力；\n④拓宽农民合作社服务范围，推动乡村产业融合发展。",
        "answer": "大数据时代是信息爆炸的时代，产生的海量数据具有巨大的价值，但同时也带来了许多安全问题。大数据时代的基本特征包括数据体量巨大、数据类型多样、处理速度快和价值密度低。当前大数据信息安全存在隐私泄露、黑客攻击和数据存储安全等问题。",
        "reason": "待判答案与标准答案的关联性极低，题目和标准答案的内容围绕家庭农场和乡村经济等内容，待判答案讲述大数据的内容，两者基本毫无关联",
        "score": 1
        # }, {
        #     "information": "新型冠状病毒肺炎是近百年来人类遭遇的影响范围最广的全球性大流行病，对全世界是一次严重危机和严峻考验。人类生命安全和健康面临重大威胁。\n面对突如其来、来势汹汹的疫情天灾，中国果断打响疫情防控阻击战，把人民生命安全和身体健康放在第一位，采取最全面最严格最彻底的防控措施，取得了抗击疫情重大战略成果。中国始终秉持人类命运共同体理念，肩负大国担当，同其他国家并肩作战、共克时艰，毫无保留同各方分享防控和救治经验，尽己所能向国际社会提供人道主义援助，支持全球抗击疫情。\n2020年3月26日，国家主席习近平出席二十国集团领导人特别峰会并发表《携手抗疫共克时艰》讲话，倡议打好新冠肺炎疫情防控全球阻击战，有效开展国际联防联控，积极支持国际组织发挥作用，加强国际宏观经济政策协调。",
        #     "question": "结合材料并运用政治生活知识，分析打赢新冠肺炎疫情防控全球阻击战为什么要秉持人类命运共同体理念。",
        #     "standard_answer": "①国家利益是国际关系的决定因素，共同利益是国际合作的基础。秉持人类命运共同体理念，加强国际合作，携手赢得这场人类同重大传染性疾病的斗争，是各国共同利益之所在。\n②和平与发展是当今时代的主题（或：维护世界和平、促进共同发展是我国外交政策的宗旨）。中方秉持人类命运共同体理念，愿向其他国家提供力所能及的援助，为世界经济稳定作出贡献。\n③秉持人类命运共同体理念符合我国外交政策中维护国家主权、安全和发展利益，促进世界和平与发展的目标；符合我国平等互利、和平共处的外交基本准则。\n④在当今的国际社会，维护和保障人权是一项基本道义原则。是否合乎保障人权的要求已成为评判一个集体（无论是政治上的还是经济上的）优劣的重要标准。坚持人类命运共同体理念，坚决打赢疫情防治攻坚战，有利于尊重和保障人权。\n⑤我国是人民民主专政的社会主义国家，人民是国家的主人，坚持人类命运共同体理念，是保障人民主人翁地位的体现。",
        #     "answer": "大数据时代是信息爆炸的时代，产生的海量数据具有巨大的价值，但同时也带来了许多安全问题。大数据时代的基本特征包括数据体量巨大、数据类型多样、处理速度快和价值密度低。当前大数据信息安全存在隐私泄露、黑客攻击和数据存储安全等问题。",
        #     "reason": "待判答案与标准答案的关联性极低，题目和标准答案的内容围绕新冠病毒和国际利益、人类命运共同体等内容，待判答案讲述大数据的内容，两者基本毫无关联",
        #     "score": 1
    }]

    example_str = '\n\n'.join(
        [subjective_question_prompt_example_formmater.format(ques_idx=(idx + 1),
                                                             question=i['information'] + '\n' + i['question'],
                                                             standard_answer=i['standard_answer'],
                                                             answer=i['answer'], reason=i['reason'], score=i['score'])
         for idx, i in enumerate(questions)])

    input = subjective_question_formmaters[4].format(ques_example=example_str, ques_title=ques_title,
                                                     ques_answer=standard_answer, answer=model_output)
    # print('-' * 10, flush=True)
    # print(input, flush=True)
    response = llm_model.chat(input)
    # print(type(response), response, end='\n', flush=True)

    score = status = 0
    reason = ''
    try:
        # print(response, flush=True)
        output_score_re = re.match(subjective_question_response_re_formater, response)

        if output_score_re:
            reason = output_score_re.group(1)
            score = round(float(output_score_re.group(2)), 2)
            status = 1
        else:
            print(f"output_score_re is {output_score_re}", flush=True)
    except Exception as e:
        print(f'Exception in get_chatglm_score_by_gaokao: {str(e)}', flush=True)
    return status, score, reason, response


@chatglm_bp.route('/gaokao_create_subjective_question', methods=['POST'])
def gaokao_create_subjective_question():
    st = datetime.datetime.now()
    for ques_idx, ques in enumerate(gaokao_questions):
        ques_title = get_ques_content(ques['question'])

        answer = ques['model_output'].split('【答案】')[1]
        status, score, reason, response = get_chatglm_score_by_gaokao(ques_title, ques['standard_answer'], answer)

        try:
            ques_record = Question(ques_tagid=4, ques_title=ques_title, ques_answer=ques['standard_answer'],
                                   ques_score=int(ques['score']), content=response, status=status)
            db.session.add(ques_record)
            db.session.commit()
        except:
            db.session.rollback()

        try:
            as_record = AutoScore(question_id=ques_record.id, answer=answer, llm_score=float(score),
                                  expert_score=round(
                                      float(ques['model_correction_score'][0]) / float(ques['score']) * 10,
                                      2),
                                  status=status, model_name=model_name, llm_output=response)
            db.session.add(as_record)
            db.session.commit()
        except:
            db.session.rollback()

        et = datetime.datetime.now()
        print(f'{ques_idx+1}/{len(gaokao_questions)}, during: {(et-st).seconds}s', flush=True)

    return success_res()


@chatglm_bp.route('/chat', methods=['POST'])
def chat():
    input = request.json.get('input', '')
    response = llm_model.chat(input)
    return jsonify({'output': response})


@chatglm_bp.route('/stream_chat', methods=['POST'])
def stream_chat():
    input = request.json.get('input', '')
    history = request.json.get('history', [])

    history_template = []
    for user, assis in history:
        history_template.append({'role': 'user', 'content': user})
        history_template.append({'role': 'assistant', 'content': assis})

    def generate():
        # history = [{'role':'user', 'content':''}, {'role':'assistant', 'content':''}]
        for response, history, past_key_values in llm_model.model.stream_chat(llm_model.tokenizer, input,
                                                                              history=history_template, temperature=.1,
                                                                              top_k=1, top_p=.1,
                                                                              return_past_key_values=True, ):
            # print(response, flush=True)
            # print(response, flush=True)
            # print('+' * 10, flush=True)
            # print([i.keys() for i in history], flush=True)
            # print('+' * 10, flush=True)
            # print([type(ii) for i in past_key_values for ii in i], flush=True)
            # print('*' * 50, flush=True)
            yield response

        print(history, flush=True)

    return app.response_class(stream_with_context(generate()))


@chatglm_bp.route('/create_questions_from_static_file', methods=['POST'])
def create_questions_from_static_file():
    file_name = request.json.get('file_name', '')
    ques_tagid = request.json.get('ques_tagid', 1)
    file_path = os.path.join(os.getcwd(), 'static', file_name)
    if os.path.exists(file_path):
        with open(file_path, 'r', encoding='utf-8') as f:
            file_data = json.loads(f.read())
        for content in file_data:
            flag, res = llm_create_objective_question(content, ques_tagid, batch=True,
                                                      datacollection_name=file_name.split('.')[0])
            if not flag:
                print(content, res, flush=True)
        return success_res()
    else:
        return fail_res(msg="文件不存在")


@chatglm_bp.route('/content_run_formatter', methods=['POST'])
def content_run_formatter():
    content = request.json.get('content', '')
    ques_tagid = request.json.get('ques_tagid', 1)

    flag, res = llm_create_objective_question(content, ques_tagid, batch=False, datacollection_name='test_in_python')
    print("结果：", flag, res)
    return success_res()


@chatglm_bp.route('/create_questions_from_static_all_files', methods=['POST', 'GET'])
def create_questions_from_static_all_files():
    file_name = ['entity_summary.json', 'computer_science.json']
    ques_tagids = [1, 3]
    st = datetime.datetime.now()
    for file_name in file_name:
        file_path = os.path.join(os.getcwd(), 'static', file_name)
        with open(file_path, 'r', encoding='utf-8') as f:
            file_data = json.loads(f.read())
        for idx, content in enumerate(file_data):
            for ques_tagid in ques_tagids:
                flag, res = llm_create_objective_question(content, ques_tagid, batch=True,
                                                          datacollection_name=file_name.split('.')[0])
                et = datetime.datetime.now()
            print(f'{file_name}: {idx+1}/{len(file_data)}, during: {round((et - st).seconds / 60, 2)}mins', flush=True)
    return success_res()
